package com.whz.generic.spring;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.commons.util.InetUtilsProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.lang.NonNull;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author whz
 */
@Slf4j
@Configuration
public class SpringUtils implements ApplicationContextAware {
    public static final String[] OTHER = new String[0];
    private static ApplicationContext ApplicationContext;

    /**
     * @param applicationContext the ApplicationContext object to be used by this object
     */
    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
        ApplicationContext = applicationContext;
    }

    public static Optional<ApplicationContext> getApplicationContext() {
        if (ApplicationContext == null) {
            return Optional.empty();
        }
        return Optional.of(ApplicationContext);
    }

    public static <T> Optional<T> getBean(Class<T> clz) {
        if (ApplicationContext == null) {
            return Optional.empty();
        }
        try {
            return Optional.of(ApplicationContext.getBean(clz));
        } catch (Exception e) {
            log.warn("getBean(Class:[" + clz.getSimpleName() + "]) error.", e);
        }
        return Optional.empty();
    }

    /**
     * 查询多个指定类型的bean
     *
     * @param clz 类型
     * @param <T> 参数类型
     * @return beans
     */
    public static <T> Optional<List<T>> getBeans(Class<T> clz) {
        if (ApplicationContext == null) {
            return Optional.empty();
        }
        List<T> beans = Stream.of(ApplicationContext.getBeanNamesForType(clz))
                              .map(name -> ApplicationContext.getBean(name, clz))
                              .collect(Collectors.toList());
        if (CollUtil.isEmpty(beans)) {
            return Optional.empty();
        }
        return Optional.of(beans);
    }

    /**
     * 查询当前服务名,即spring.application.name
     */
    public static String currentServiceName() {
        return currentEnvironment().map(env -> env.getProperty("spring.application.name")).orElse("");
    }

    /**
     * 查询当前环境值 dev,qa,prod,prod2
     *
     * @return dev, qa, prod, prod2
     */
    public static String[] currentActiveProfiles() {
        return currentEnvironment().map(Environment::getActiveProfiles).orElse(OTHER);
    }

    /**
     * 获取当前spring环境
     *
     * @return {@link Environment}
     */
    public static Optional<Environment> currentEnvironment() {
        return getBean(Environment.class);
    }

    /**
     * 获取当前网络配置
     *
     * @return InetUtils
     */
    public static InetUtils getInetUtils() {
        return getBean(InetUtils.class).orElse(new InetUtils(new InetUtilsProperties()));
    }

    /**
     * 发布应用事件
     *
     * @param event 事件
     */
    public static void publishEvent(ApplicationEvent event) {
        if (event != null) {
            getApplicationContext().ifPresent(applicationContext -> {
                applicationContext.publishEvent(event);
            });
        }
    }
}